﻿using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Bricks.Injecting;

namespace Motar.ServiceModel
{

    /// <summary>
    /// Factory that provides instances of Motar.ServiceModel.InjectingServiceHost in managed
    /// hosting environments where the host instance is created dynamically in response
    /// to incoming messages.
    /// </summary>
    public class InjectingServiceHostFactory : ServiceHostFactoryBase
    {

        /// <summary>
        /// Initializes a new instance of the Motar.ServiceModel.InjectingServiceHostFactory
        /// class.
        /// </summary>
        public InjectingServiceHostFactory() :
            this(ServiceLocator.Current)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="containerFacade"></param>
        protected InjectingServiceHostFactory(IContainerFacade containerFacade) :
            base()
        {
            if (containerFacade == null)
            {
                throw new ArgumentNullException("containerFacade");
            }
            _containerFacade = containerFacade;
        }

        /// <summary>
        /// 
        /// </summary>
        private readonly IContainerFacade _containerFacade;

        /// <summary>
        /// 
        /// </summary>
        protected virtual IContainerFacade ContainerFacade
        {
            get { return _containerFacade; }
        }

        /// <summary>
        /// Creates a System.ServiceModel.ServiceHost with specific base addresses and
        /// initializes it with specified data.
        /// </summary>
        /// <param name="constructorString">The initialization data passed to the System.ServiceModel.ServiceHostBase instance being constructed by the factory.</param>
        /// <param name="baseAddresses">The System.Array of type System.Uri that contains the base addresses for the service hosted.</param>
        /// <returns>A System.ServiceModel.ServiceHost with specific base addresses.</returns>
        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            Type serviceType = Type.GetType(constructorString);

            return CreateServiceHost(serviceType, baseAddresses);
        }

        /// <summary>
        /// Creates a System.ServiceModel.ServiceHost for a specified type of service
        /// with a specific base address.
        /// </summary>
        /// <param name="serviceType">Specifies the type of service to host.</param>
        /// <param name="baseAddresses">The System.Array of type System.Uri that contains the base addresses for the service hosted.</param>
        /// <returns>A System.ServiceModel.ServiceHost for the type of service specified with a specific base address.</returns>
        protected virtual ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            ServiceBehaviorAttribute serviceBehaviour = serviceType.GetCustomAttributes(typeof(ServiceBehaviorAttribute), true).SingleOrDefault() as ServiceBehaviorAttribute;

            if (serviceBehaviour == null)
            {
                return new ServiceHost(serviceType, baseAddresses).ApplyInjectingBehavior();
            }
            else
            {
                switch (serviceBehaviour.InstanceContextMode)
                {
                    case InstanceContextMode.Single:

                        object singletonInstance = ContainerFacade.Resolve(serviceType);

                        return new ServiceHost(singletonInstance, baseAddresses).ApplyInjectingBehavior();

                    default:

                        return new ServiceHost(serviceType, baseAddresses).ApplyInjectingBehavior();
                }
            }
        }
    }
}
